function Opts = geneOpts(Components,OffsetNM,TrendNM,CommonFolder,CommonAdd,Lmin,Lmax)
%geneOpts - StaVel options struct variable generation
%
%   Opts = geneOpts(Components,OffsetNM,TrendNM,CommonFolder,CommonAdd,Lmin,Lmax)
%
% This function generates the struct variable Opts to be used by StaVelMain
% and functions called by it.
% Input arguments:
% - Components: vector of components, where 0 means East, 1 means North and
%   2 means Vertical. For example, to analize horizontal components only,
%   components is [0 1].
%   If Components is undefined or empty, Components = [0 1 2] is used.
% - OffsetNM: Noise models to be used for offset recognition. Allowed values 
%   are the strings:
%       'FNWN' (flicker noise and white noise)
%       'PLWN' (power law and white noise)
%       'RWFNWN' (random walk noise, flicker noise and white noise)
%       'WN' (whote noise)
%   If OffsetNM is undefined, empty of is no an allowed string, the default
%   choice WN is used.
% - TrendNM: Noise models to be used for trend computation. The argument
%   must be either an allowed string (see below the list of allowed strings)
%   for the case of a single noise model or a cell variable whose elements 
%   are allowed strings for the case of multiple noise models. The allowed
%   strings are:
%       'WN' (white noise)
%       'GGM' (generalised Gauss-Markov)
%       'fGGM' (k-fixed GGM)
%       'FN' (flicker noise)
%       'FNGGM' (flicker noise GGM)
%       'RW' (random walk)
%       'RWGGM' (random walk GGM)
%       'PL' (power law)
%       'PLGGM' (power law GGM)
%       'MT' (matern)
%       'VA' (varying annual)
%       'VSA' (varying semi annual)
%       'AR1' (ARMA)          
%   If TrendNM is undefined, empty, or no valid strings are in TrendNM, the
%   default choice {'WN', 'PL'} is used.
% - CommonFolder is an optional general folder, subfolder of the main StaVel
%   folder, that will contain all the folders generated/filled by StaVelMain. 
%   If CommonFolder is undefined or empty, the general folder is the main
%   StaVel folder. 
% - CommonAdd is the common string to be added o the file name. Options:
%   - it is a char (included the empty char ''): it is used for all the 
%     generated files. For example, the generated raw file for a station
%     NAME is './raw_files/NAME.EU.mom' if EU is CommonAdd and
%     './raw_files' is the raw files folder. If CommonAdd is '', in the
%     same conditions the raw file is './raw_files/NAME.mom'.
%   - it is not a char (included []). No a common string is used and each
%     generated file can have a specific added string (these strings are
%     defined by editing the present function). 
% - Lmin and Lmax are the optional minimum and maximum lengths of the GNSS
%   time series, expressed in years. If Lmin (Lmax) is undefined or empty,
%   no minumum length (no maximum length) is considered.
%
% In order not to make it necessary to introduce a complex user interface 
% that is not compatible with GNU Octave, the fields relating to the names 
% of the folders of the files generated or modified directly and indirectly 
% by StaVelMain are managed by acting on the program lines of the geneOpts 
% function (it is recommended to always have a backup copy of this function 
% in order to facilitate any future changes).
% 
% Example: the output generated with the command line
%    OptsGen = geneOpts([],'PLWN',{'PL','WN'},'','.EU',0)
% and the default geneOpts values is
%         dirEnv: './tenv_files'
%          dirTs: './ts_files'
%         dirRaw: './raw_files'
%         dirObs: './obs_files'
%         dirPre: './pre_files'
%         dirMom: './mom_files'
%      dirPreCME: './preCME_files'
%      dirMomCME: './momCME_files'

%         dirCtl: './ctl_files'
%         dirOut: './out_files'
%        dirJSON: './JSON_files'
%      dirHector: '/mnt/c/GNSS/hector/'
%        extTenv: '.tenv3'
%     components: []
%         AddEnv: '.EU'
%          AddTs: '.EU'
%         AddRaw: '.EU'
%         AddObs: '.EU'
%         AddPre: '.EU'
%         AddMom: '.EU'
%      AddPreCME: '.EU'
%      AddMomCME: '.EU'
%         AddOut: '.EU'
%        AddJSON: '.EU'
%           Lmin: 0
%           Lmax: []
%        Offsets: [1×1 struct]
%       Outliers: [1×1 struct]
%          Trend: [1×1 struct]
%
% The values of the Offset, Outlier and Trend fields are themselves struct 
% variables, established on the basis of the options chosen by the input 
% options of geneOpt and the choices on foldernames. These values act on 
% generation of the corresponding Hector control (.ctl) files by StaVelMain. 
%
%   Opts = geneOpts(Components,OffsetNM,TrendNM,CommonFolder,CommonAdd,Lmin,Lmax)
%
% See also StaVelMain, InspOffsetMom, InspectOffsetSearch. 

% G. Teza, 2022

if nargin < 7
    Lmax = [];
end
if nargin < 6
    Lmin = [];
end
if nargin < 5 || (isempty(CommonAdd) && ~ischar(CommonAdd)) || ~ischar(CommonAdd)
    CommonAddOption = false;
else
    CommonAddOption = true;
end
if nargin < 4
    CommonFolder = [];
end
if nargin >= 3 && ischar(TrendNM)
    TrendNM = {TrendNM};
end
if nargin < 3 || isempty(TrendNM) || (sum(ismember(TrendNM,{...
        'WN','GGM','fGGM','FN','FNGGM','RW','RWGGM','PL','PLGGM','MT',...
        'VA','VSA','AR1'})) == 0)
    TrendNM = {'WN','PL'};
end 
if nargin < 2 || isempty(OffsetNM) || ~ismember({OffsetNM},{'FNWN','PLWN','RWFNWN','WN'})
    OffsetNM = 'WN';
end
if (nargin < 1) || isempty(Components)
    Components = [0 1 2];
end

%% General options: 

if isempty(CommonFolder)
    strCommFold = '';
else
    strCommFold = [CommonFolder '/'];
end

Opts = struct('dirEnv',['./' strCommFold 'tenv_files']);
Opts.dirTs  = ['./' strCommFold 'ts_files'];
Opts.dirRaw = ['./' strCommFold 'raw_files'];
Opts.dirObs = ['./' strCommFold 'obs_files'];
Opts.dirPre = ['./' strCommFold 'pre_files'];
Opts.dirMom = ['./' strCommFold 'mom_files'];
Opts.dirPreCME = ['./' strCommFold 'preCME_files'];
Opts.dirMomCME = ['./' strCommFold 'momCME_files'];
Opts.dirCtl = ['./' strCommFold 'ctl_files'];
Opts.dirOut = ['./' strCommFold 'out_files'];
Opts.dirJSON = ['./' strCommFold 'JSON_files'];
Opts.dirHector = '/mnt/c/GNSS/hector/';
Opts.extTenv = '.tenv3';
Opts.components = Components;

if CommonAddOption
    Opts.AddEnv = CommonAdd;   % optional additional string for Env or Neu files
    Opts.AddTs  = CommonAdd;   % optional additional string for Ts files 
    Opts.AddRaw = CommonAdd;   % optional additional string for Raw files
    Opts.AddObs = CommonAdd;   % optional additional string for Obs files
    Opts.AddPre = CommonAdd;   % optional additional string for Pre files
    Opts.AddMom = CommonAdd;   % optional additional string for final Mom files
    Opts.AddPreCME = CommonAdd;   % optional additional string for Pre CME-free files
    Opts.AddMomCME = CommonAdd;   % optional additional string for final Mom CME-free files
    Opts.AddOut = CommonAdd;   % optional additional string for Out files
    Opts.AddJSON = CommonAdd;  % optional additional string for JSON files
else
    Opts.AddEnv = '.EU';   % optional additional string for Neu files
    Opts.AddTs  = '.EU';   % optional additional string for Ts files 
    Opts.AddRaw = '.EU';   % optional additional string for Raw files
    Opts.AddObs = '.EU';   % optional additional string for Obs files
    Opts.AddPre = '.EU';   % optional additional string for Pre files
    Opts.AddMom = '.EU';   % optional additional string for final Mom files
    Opts.AddPreCME = '.EU';   % optional additional string for Pre CME-free files
    Opts.AddMomCME = '.EU';   % optional additional string for final Mom CME-free files
    Opts.AddOut = '.EU';   % optional additional string for Out files
    Opts.AddJSON = '.EU';  % optional additional string for JSON files
end

Opts.Lmin = Lmin;
Opts.Lmax = Lmax;

%% Offsets recognition options:

Opts.Offsets.interpolate  = 'no';
Opts.Offsets.PhysicalUnit = 'mm';
Opts.Offsets.ScaleFactor  = 1.0;
if strcmpi(OffsetNM,'FNWN')
    Opts.Offsets.NoiseModels = 'FlickerGGM White';
elseif strcmpi(OffsetNM,'PLWN')
    Opts.Offsets.NoiseModels = 'GGM White';
elseif strcmpi(OffsetNM,'RWFNWN')
    Opts.Offsets.NoiseModels = 'FlickerGGM White';
else
    Opts.Offsets.NoiseModels = 'White';
end
Opts.Offsets.seasonalsignal = 'yes';
Opts.Offsets.halfseasonalsignal = 'yes';
Opts.Offsets.estimateoffsets = 'yes';
Opts.Offsets.JSON = 'yes';
Opts.Offsets.beta_size = 5.0;
Opts.Offsets.beta_spacing = 8.5;
Opts.Offsets.offsets_3D = 'yes';
Opts.Offsets.GGM_1mphi = 6.9e-06;
Opts.Offsets.BIC_c_ExtraPenalty = 0;

%% remove outliers options: 

Opts.Outliers.interpolate  = 'no';
Opts.Outliers.PhysicalUnit = 'mm';
Opts.Outliers.ScaleFactor  = 1.0;
Opts.Outliers.seasonalsignal = 'yes';
Opts.Outliers.halfseasonalsignal = 'yes';
Opts.Outliers.estimateoffsets = 'yes';
Opts.Outliers.IQ_factor = 3.0;
Opts.Outliers.JSON = 'yes';
Opts.Outliers.estimatepostseismic = 'no';
Opts.Outliers.estimateslowslipevent = 'no';

%% trend evaluation options:

Opts.Trend.interpolate  = 'no';
Opts.Trend.PhysicalUnit = 'mm';
Opts.Trend.ScaleFactor  = 1.0;
Opts.Trend.seasonalsignal = 'yes';
Opts.Trend.halfseasonalsignal = 'yes';
Opts.Trend.estimateoffsets = 'yes';
Opts.Trend.JSON = 'yes';

need_1mphi = false;
need_varying_phi = false;
strTNM = [];
if ismember({'WN'},TrendNM)
    strTNM = [strTNM 'White'];
end
if ismember({'GGM'},TrendNM) || ismember('fGGM',TrendNM)
    strTNM = [strTNM ' GGM'];
end
if ismember({'FN'},TrendNM)
    strTNM = [strTNM ' Flicker'];
end
if ismember({'FNGGM'},TrendNM)
    strTNM = [strTNM ' FlickerGGM'];
    need_1mphi = true;
end
if ismember({'RW'},TrendNM)
    strTNM = [strTNM ' RandomWalk'];
end
if ismember({'RWGGM'},TrendNM)
    strTNM = [strTNM ' RandomWalkGGM'];
    need_1mphi = true;
end
if ismember({'PL'},TrendNM)
    strTNM = [strTNM ' Powerlaw'];
end
if ismember({'PLGGM'},TrendNM)
    strTNM = [strTNM ' GGM'];
    need_1mphi = true;
end
if ismember({'MT'},TrendNM)
    strTNM = [strTNM ' Mater'];
    need_1mphi = true;
end
if ismember({'VA'},TrendNM)
    strTNM = [strTNM ' VaryingAnnual'];
    need_varying_phi = true;
end
if ismember({'VSA'},TrendNM)
    strTNM = [strTNM ' VaryingSemiAnnual'];
    need_varying_phi = true;
end           
if ismember({'AR1'},TrendNM)
    strTNM = [strTNM ' ARMA'];
    Opts.Trend.AR_p = 1;
    Opts.Trend.MA_q = 0;
end
if need_1mphi
    Opts.Trend.GGM_1mphi = 6.9e-06;
end
if need_varying_phi
    Opts.Trend.phi_varying_fixed = 0.9999;
end
if ismember({'fGGM'},TrendNM)    
    Opts.Trend.GGM_1mphi = 0.02;
    Opts.Trend.kappa_fixed = -1.0;
end
Opts.Trend.NoiseModels = strTNM;